package com.vertx.starter;

import com.google.common.base.Stopwatch;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.vertx.starter.guice.GuiceVerticalFactory;
import io.vertx.core.Future;
import io.vertx.core.Vertx;
import lombok.extern.log4j.Log4j2;

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.TimeUnit;

@Log4j2
public class AppAppServiceLauncherImpl implements AppServiceLauncher {

    private Injector injector;

    @Inject
    public AppAppServiceLauncherImpl(Injector injector) {
        this.injector = injector;
    }

    @Override
    public Future<Vertx> launch(Vertx vertx) {
        log.info("开始启动服务!");
        vertx.exceptionHandler((e) -> {
            log.error("未捕获异常!", e);
        });
        this.registerRequiredVerticalFactory(vertx);
        Stopwatch stopWatch = Stopwatch.createStarted();
        return this.deployRootVerticals(vertx).onFailure((e) -> {
            log.error("失败启动服务!", e);
        }).onComplete((__) -> {
            log.info("结束启动服务!耗时: {}ms", stopWatch.elapsed(TimeUnit.MILLISECONDS));
        }).map((__) -> vertx);
    }

    private void registerRequiredVerticalFactory(Vertx vertx) {
        vertx.registerVerticleFactory(new GuiceVerticalFactory(this.injector));
    }

    private Future<Void> deployRootVerticals(Vertx vertx) {
        AppVerticalDeployAgent deployer = AppVerticalDeployAgent.create(vertx);
        LinkedList<Class<? extends AppVerticle>> verticalClazzQueue = new LinkedList();
        verticalClazzQueue.add(MainVerticle.class);
        return this.deployVerticalSequentially(deployer, verticalClazzQueue).mapEmpty();
    }

    private Future<String> deployVerticalSequentially(AppVerticalDeployAgent deployer, Queue<Class<? extends AppVerticle>> verticalClazzQueue) {
        if (verticalClazzQueue.isEmpty()) {
            return Future.succeededFuture();
        } else {
            Class<? extends AppVerticle> clazz = (Class) verticalClazzQueue.poll();
            return deployer.deployVerticle(clazz).compose((__) -> {
                return this.deployVerticalSequentially(deployer, verticalClazzQueue);
            });
        }
    }

}
